/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package agents;

import env.Action;
import env.Enviroment;
import env.Tile;

/**
 *
 * @author user
 */
public class AgentState {

    private Tile tile;
    private Action lastMotion; //what got me here? only used with ice
    private int score;
    private boolean alive;
    private int bullets;

   // private int moves;

    public AgentState(int row, int col, Action lastAction, int score, boolean alive, int bullets) {
        this(Enviroment.env.getTile(row, col), lastAction, score, alive, bullets);
    }

    private AgentState(Tile tile, Action lastMotion, int score, boolean alive, int bullets) {
        this.tile = tile;
        this.lastMotion = lastMotion;
        this.score = score;
        this.alive = alive;
        this.bullets = bullets;
    }

    public int getCol() {
        return tile.getCol();
    }

    public int getRow() {
        return tile.getRow();
    }

    public Action getLastAction() {
        return lastMotion;
    }

    public void incScore(int n) {
        score += n;
    }

    public void decScore(int n) {
        score -= n;
    }

    private void updatePosition(Action move) {
        //just moved into ice (and not stopped already):
        if (move == Action.shoot && bullets>0) {
            bullets--;
        }
        if (tile.isIce() && this.lastMotion != null) {
            final Tile neighbor = tile.getNeighbor(this.lastMotion);
            if(neighbor==null)
                System.err.println("move="+move+" , "+this);
            if (neighbor.isWall()) {
                move = null; //crash
            } else {
                move = lastMotion; //slide
            }
        }
        if (move != null && move != Action.shoot) {
            Tile nextTile = tile.getNeighbor(move);
            //just to make sure not attempting to be in wall or outside map:
            if (nextTile != null && !nextTile.isWall()) {
                tile = nextTile;
            }
        }
        
       // score--;
        lastMotion = move;
        //moves++;
    }

    public boolean isLegalMove(Action move) {
        if (getTile().isIce() && lastMotion!=null && move != this.lastMotion) {
            return false;
        }
        else if(move==Action.shoot)
            return bullets>0;
        final Tile targetTile = getTile().getNeighbor(move);
        return targetTile != null && !targetTile.isWall();
    }

    public AgentState clone(Action move,boolean slipped) {
    	AgentState as =  clone(move);
    	if (!slipped)
    		as.lastMotion = null;
    	return as;
    }

    public AgentState clone(Action move) {
        AgentState s = new AgentState(tile, lastMotion, score, alive, bullets);
        if(move!=null && alive)
            s.updatePosition(move);
        return s;
    }

    public Tile getTile() {
        return tile;
    }

    public boolean isAlive() {
        return alive;
    }

    public void setAlive(boolean alive) {
        this.alive = alive;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public int getBullets() {
        return bullets;
    }

    public void setBullets(int bullets) {
        this.bullets = bullets;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AgentState other = (AgentState) obj;
        if (this.tile != other.tile && (this.tile == null || !this.tile.equals(other.tile))) {
            return false;
        }
        if ((tile.isIce() || lastMotion==Action.shoot) &&  this.lastMotion != other.lastMotion) {
            return false;
        }
        if (this.score != other.score) {
            return false;
        }
        if (this.alive != other.alive) {
            return false;
        }
        if (this.bullets != other.bullets) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + (this.tile != null ? this.tile.hashCode() : 0);
        if (tile.isIce() || lastMotion==Action.shoot)
            hash = 79 * hash + (this.lastMotion != null ? this.lastMotion.hashCode() : 0);
        hash = 79 * hash + this.score;
        hash = 79 * hash + (this.alive ? 1 : 0);
        hash = 79 * hash + this.bullets;
        return hash;
    }


    /* TODO: important!!! if you can prove you can use this set of equals and hashcode, the search
     * will be MUCH FASTER!!!!
     *
     */
    /*
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AgentState other = (AgentState) obj;
        if (this.tile != other.tile) {
            return false;
        }

        if (tile.isIce() &&  this.lastAction != other.lastAction) { //lastAction only matters on icy tiles?
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = this.tile.hashCode();
        if (tile.isIce()) {
            hash = 41 * hash + (this.lastAction != null ? this.lastAction.hashCode() : 0); //lastAction only matters on icy tiles?
        }
//        hash = 41 * hash + (this.lastAction != null ? this.lastAction.hashCode() : 0); //lastAction only matters on icy tiles?
        return hash;
    }
*/


    @Override
    public String toString() {
        return (alive ? "" : "DEAD ") + tile + " score=" + score + " last=" + lastMotion + " "+bullets+" bullets";
    }
}
